package it.softphone.cmc.server.rest.scriptlet;

import it.softphone.cmc.server.rest.CMCRestException;
import it.softphone.cmc.server.rest.RESTServiceAware;
import it.softphone.cmc.server.service.ScriptletManagerService;
import it.softphone.cmc.server.service.TaskQueueService;
import it.softphone.cmc.server.service.util.BasicHttpUtil;
import it.softphone.cmc.shared.entity.Asset;
import it.softphone.cmc.shared.entity.ScriptletAsset;
import it.softphone.commons.exception.NullParameterException;
import it.softphone.commons.service.LogAware;
import it.softphone.commons.spring.ApplicationConfig;

import java.io.IOException;
import java.io.Reader;
import java.net.MalformedURLException;

import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;


/**
 * 
 * @author softphone
 *
 */
public abstract class CMCAbstractScriptletExecutionManager extends RESTServiceAware implements LogAware {

    private static final String ASYNC_REASON_PARAM = "async_reason";
	private static final String ASYNC_CODE_PARAM = "async_code";
	private static final String ASYNC_RESULT_PARAM = "result"; // DEFAULT PARAM NAME
	
	private static final String REDIRECT_RESULT_PARAM = "redirect_result";

	/**
     * 
     * @param scriptlet
     * @return
     */
	protected String tenantFromAsset( Asset scriptlet ) {
		if( scriptlet == null ) throw new NullParameterException("scriptlet");
		
		final String groupId = scriptlet.getGroupId();
		
		return ( groupId==null || "system".equalsIgnoreCase(groupId) ) ? tenant().getSystemTenant() : groupId;
	}
	
    /**
     * 
     * @param redirect_uri
     * @return
     */
    private void resposeRedirectUri( String redirect_uri, String async_result, Response.Status code, String result ) throws CMCRestException {
    	if( redirect_uri == null ) throw new NullParameterException("redirect_uri");
    	
    	logger.debug( String.format("resposeRedirectUri\nuri=[%s]\nstatus=[%s]\nresult=[%s]", 
    							redirect_uri,
    							code,
    							result));
    	
    	if( !NO_REDIRECT.equals(redirect_uri)) {
			try {
				java.net.URL url = new java.net.URL( redirect_uri );
				
		    	//java.util.Map<String,String> params = Collections.emptyMap();
		    	java.util.Map<String,String> params = new java.util.HashMap<String,String>(1);
		    	params.put(ASYNC_CODE_PARAM, Integer.toString(code.getStatusCode()));
		    	params.put(ASYNC_REASON_PARAM, code.getReasonPhrase());
		    	params.put(async_result, result);
		    	
		    	BasicHttpUtil.post(false, url, params, new BasicHttpUtil.Callback() {
	
					@Override
					public void onSuccess(Reader result) {
						logger.info("redirect uri success " );
					}
	
					@Override
					public void onError(Throwable ex) {
						logger.info("redirect uri error " );				
					}
		    		
		    	});
	
				
			} catch (MalformedURLException e) {
				logger.error( "resposeRedirectUri", e);
			} catch (IOException e) {
				logger.error( "resposeRedirectUri", e);
			}
    	}

    }
    
    /*
     * 
     * 
     */
    private String getAsyncResultParamName( MultivaluedMap<String, String> params ) {
    	
		final String async_result = params.getFirst(REDIRECT_RESULT_PARAM);
		
		return (async_result==null) ? ASYNC_RESULT_PARAM : async_result;

    }
    /**
     * 
     * @param key
     * @param params
     * @return
     */
    public String execScriptletSync( String key, HttpHeaders hh, UriInfo ui, MultivaluedMap<String, String> params, String method ) throws CMCRestException {

		ScriptletManagerService service = ApplicationConfig.getBean(ScriptletManagerService.class);

		ScriptletAsset s = service.findScriptletByKey(key);

		String result = ""; // empty result

		if (s != null) {

			final String redirect_uri = params.getFirst(REDIRECT_URI_PARAM);
			final String async_result = getAsyncResultParamName(params);

			try {

				Object sresult = service.execScriptlet(s, params, hh, ui );

				String entityResult = "";

				if (sresult != null) {

					entityResult = sresult.toString();
					
				} else {
					final String msg = String.format("exec scriptlet [%s] result is empty", key);
					logger.debug(msg);
				}

				if (redirect_uri != null) {
					resposeRedirectUri(redirect_uri, async_result, Status.OK,entityResult);
				} else {
					result = entityResult;
				}

			} catch (NoSuchMethodException e) {

				final String msg = "main function not found in script";
				logger.warn(msg, e);
				if (redirect_uri != null) {
					resposeRedirectUri(redirect_uri, async_result,  Status.BAD_REQUEST, msg);
				} else {
					
					throw new CMCRestException(Status.BAD_REQUEST,msg);
				}

			} catch (Throwable e) {
				final String msg = "error during script evaluation";
				logger.warn(msg, e);

				if (redirect_uri != null) {
					resposeRedirectUri(redirect_uri, async_result, Status.INTERNAL_SERVER_ERROR, msg);
				} else {
					throw new CMCRestException(Status.INTERNAL_SERVER_ERROR,msg,e);
				}
			}
		} else {
			final String msg = String.format(
					"execScriptlet: Scriptlet [%s] doesn't found!", key);
			logger.debug(msg);

			throw new CMCRestException(Status.INTERNAL_SERVER_ERROR,msg);
		}

		return result;
    }
    
    /**
     * 
     * @param key
     * @param hh
     * @param baseUri
     * @param params
     * @return
     */
    protected void execScriptletAsync( String key,  HttpHeaders hh,  UriInfo ui, MultivaluedMap<String, String> params, String method  ) throws CMCRestException {

		logger.debug( String.format("execScriptletAsync [%s]\nheaders#[%d]\n[%s]\n[%s] ", key, hh.getRequestHeaders().size(), params, ui.getBaseUri() )  );

		if( logger.isDebugEnabled() ) {
			for( java.util.Map.Entry<String,java.util.List<String>> e : hh.getRequestHeaders().entrySet() ) {
				
				logger.debug( String.format("header[%s]=[%s]", e.getKey(), e.getValue() )  );
				
			}
		}
    	
		final String redirect_uri = params.getFirst(REDIRECT_URI_PARAM);
		
		if( redirect_uri==null ) {
			final String msg = String.format("Mandatory parameter '%s' has not been provided!", REDIRECT_URI_PARAM);
			logger.error( msg );
			throw new CMCRestException(Status.BAD_REQUEST,msg);
		}

    	TaskQueueService service = ApplicationConfig.getBean(TaskQueueService.class);
	
    	final String taskUri = new StringBuilder()
    								.append( ui.getBaseUri().getPath() )
    								.append( "scriptlet/exec/")
    								.append(key)
    								.toString();

    	logger.debug( String.format("execScriptletAsync taskUri[%s]", taskUri ));
    	
    	service.schedule( (HttpMethod.GET.equals(method)) ? TaskQueueService.Method.GET : TaskQueueService.Method.POST , taskUri, params, hh );
    	
    }

}
